package top.lshaci.framework.utils;

import cn.hutool.core.collection.CollUtil;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * hierarchyUtil
 *
 * @author lshaci
 * @since 1.0.8
 */
public class HierarchyUtil {

    /**
     * <p>递归设置下一级</p>
     * <pre>
     *     public class Menu {
     *         private String id;
     *         private String parentId;
     *         private List&lt;Menu&gt; children;
     *         // ...省略getter和setter方法
     *     }
     * </pre>
     *
     * @param data         所有的数据
     * @param topKey       顶层的key
     * @param getKey       Menu::getId
     * @param getParentKey Menu::getParentId
     * @param setChildren  Menu::setChildren
     * @param comparator   Comparator.comparing(Menu::getId).reversed()
     * @param <T>          数据类型
     * @param <K>          key的类型
     * @return 层级数据
     */
    public <T, K> List<T> setChildren(List<T> data, K topKey, Function<T, K> getKey, Function<T, K> getParentKey, BiConsumer<T, List<T>> setChildren, Comparator<T> comparator) {
        if (CollUtil.isEmpty(data)) {
            return Collections.emptyList();
        }
        Map<K, List<T>> dataMap = data.stream().collect(Collectors.groupingBy(getParentKey));
        List<T> top = dataMap.get(topKey).stream()
                .sorted(comparator)
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(top)) {
            return Collections.emptyList();
        }
        setChildren(top, dataMap, getKey, setChildren, comparator);
        return top;
    }

    /**
     * <p>递归设置下一级</p>
     *
     * @param top         顶层数据集合
     * @param dataMap     所有的数据Map
     * @param getKey      从单个顶层数据
     * @param setChildren 设置下一级的方法
     * @param comparator  排序方法
     * @param <T>         数据类型
     * @param <K>         key的类型
     */
    public static <T, K> void setChildren(List<T> top, Map<K, List<T>> dataMap, Function<T, K> getKey, BiConsumer<T, List<T>> setChildren, Comparator<? super T> comparator) {
        for (T t : top) {
            K key = getKey.apply(t);
            List<T> children = dataMap.get(key);
            if (CollUtil.isNotEmpty(children)) {
                children = children.stream().sorted(comparator).collect(toList());
                setChildren.accept(t, children);
                setChildren(children, dataMap, getKey, setChildren, comparator);
            }
        }
    }
}
